/*              Copyright(c) 2008 Dave Sexton              *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;

namespace DaveSexton.DocToMaml
{
	internal static class Program
	{
		#region Private / Protected
		private static readonly EventLog log = CreateEventLog();

		private const string ConversionLogFileName = "__log.txt";
		#endregion

		#region Methods
		private static EventLog CreateEventLog()
		{
			try
			{
				return new EventLog("Application", ".", "DocProject");
			}
			catch (System.Security.SecurityException)
			{
				return null;
			}
		}

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		private static void Main(string[] args)
		{
			ProgramArguments arguments = new ProgramArguments();
			arguments.Load(args);

			if (arguments.Convert || arguments.ExitCode != ExitCode.Success)
				RunConsole(arguments);
			else if (arguments.ExitCode == ExitCode.Success)
				RunUI(arguments.Project);
		}

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
		private static void RunConsole(ProgramArguments arguments)
		{
			using (ConsoleContext consoleContext = new ConsoleContext(arguments.CanAttachToParent))
			{
				try
				{
					Console.WriteLine("{0} {1} {2}", AboutForm.AssemblyTitle, AboutForm.AssemblyVersion, AboutForm.AssemblyConfiguration);
					Console.WriteLine(AboutForm.AssemblyCopyright);

					if (arguments.ExitCode != ExitCode.Success)
						ShowUsage(arguments.ExitCode);
					else if (string.IsNullOrEmpty(arguments.Project))
						ShowUsage(ExitCode.MissingProject);
					else
					{
						string log = ConvertAllInputs(arguments.Project);

						Console.WriteLine();
						Console.WriteLine("Done.");

						if (!arguments.Unattended)
						{
							Console.WriteLine();

							if (consoleContext.IsAttachedToParent)
								Console.WriteLine(log);
							else
							{
								Console.WriteLine("Press any key to view the log or 'Esc' to exit the application now.");

								if (Console.ReadKey(true).Key == ConsoleKey.Escape)
									return;
								else
								{
									Console.WriteLine();
									Console.WriteLine(log);
								}
							}
						}
					}
				}
				catch (Exception ex)
				{
					HandleConsoleException(ex);
				}

				if (!arguments.Unattended && !consoleContext.IsAttachedToParent)
				{
					Console.WriteLine();
					Console.WriteLine("Press 'Enter' to close this console window.");
					Console.ReadLine();
				}
			}
		}

		private static string ConvertAllInputs(string projectFile)
		{
			InputCollection inputs = new InputCollection();
			RuleContainer rules = new RuleContainer();
			ConceptualImageManager images = new ConceptualImageManager();
			FileGuidManager guids = new FileGuidManager();

			Project project = new Project(projectFile, inputs, rules, images, guids);
			project.Load();

			ConversionContext context = new ConversionContext(project);
			context.BeforeConvertInput += (o, e) =>
			{
				if (e.Input is FileInput)
					Console.Write(Resources.Console.ConvertingFileInput, e.Input.FullPath);
				else
					Console.Write(Resources.Console.ConvertingFolderInput, e.Input.FullPath);
			};
			context.AfterConvertInput += (o, e) =>
			{
				Console.WriteLine();
			};

			string log = null;

			try
			{
				context.ConvertAllInputs();
			}
			finally
			{
				log = project.ConversionLog;

				File.WriteAllText(Path.Combine(project.LastOutputDirectory, ConversionLogFileName), log);

				if (context.ConvertedFilesCount > 0)
					images.CreateConceptualArtFile(project.LastOutputDirectory);
			}

			return log;
		}

		private static void HandleConsoleException(Exception exception)
		{
			if (exception == null)
			{
				if (log != null)
					log.WriteEntry(Resources.Text.LogGeneralException, EventLogEntryType.Error);

				Console.WriteLine();
				Console.WriteLine("Unhandled exception.");
			}
			else
			{
				if (log != null)
					log.WriteEntry(Resources.Text.LogGeneralException + Environment.NewLine + exception.ToString(), EventLogEntryType.Error);

				Console.WriteLine();
				Console.WriteLine("Unhandled exception: {0}", exception.GetType());
				Console.WriteLine();
				Console.WriteLine(exception);
			}
		}

		private static void ShowUsage(ExitCode exitCode)
		{
			Environment.ExitCode = (int) exitCode;

			switch (exitCode)
			{
				case ExitCode.InvalidSwitch:
					Console.WriteLine();
					Console.WriteLine(Resources.Console.ErrorInvalidSwitch);
					break;
				case ExitCode.DuplicateSwitch:
					Console.WriteLine();
					Console.WriteLine(Resources.Console.ErrorDuplicateSwitch);
					break;
				case ExitCode.MissingProject:
					Console.WriteLine();
					Console.WriteLine(Resources.Console.ErrorProjectNotSpecified);
					break;
			}

			Console.WriteLine();
			Console.WriteLine(Resources.Console.Usage);
		}

		private static void RunUI(string project)
		{
			Application.EnableVisualStyles();
			Application.SetCompatibleTextRenderingDefault(false);
			Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

			using (ProgramForm form = new ProgramForm())
			{
				if (!string.IsNullOrEmpty(project))
					form.StartupProjectFile = project;

				Application.Run(form);
			}
		}

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions")]
		private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
		{
			if (log != null)
				log.WriteEntry(Resources.Text.LogGeneralException + Environment.NewLine + e.Exception.ToString(), EventLogEntryType.Error);

			if (MessageBox.Show(string.Format(System.Globalization.CultureInfo.CurrentCulture,
				Resources.Text.FatalErrorConfirmTermination, Environment.NewLine, e.Exception.Message), Resources.Text.FatalErrorCaption,
				MessageBoxButtons.YesNo, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
			{
				Environment.FailFast(e.Exception.Message);
			}
		}
		#endregion
	}
}